Questions
3 of 14
1What does HNSW stand for, and at a high level, how does it achieve sub-linear approximate nearest-neighbor search?
2What do the HNSW parameters m and ef_construct control, and what trade-off do they represent?
3What does the query-time parameter ef (search breadth) control, and how would you use it to trade off recall against latency?
4Why might increasing m significantly improve recall on one dataset but barely help - or even hurt latency - on another?
5Why does Qdrant set m: 0 on a named vector used purely for reranking (e.g. a ColBERT multivector)?
6What problem does vector quantization solve, and what is the fundamental trade-off it introduces?
7Compare scalar quantization, product quantization, and binary quantization in Qdrant in terms of compression ratio and accuracy impact.
8What are oversampling and rescoring in the context of binary quantization, and why are they necessary?
9What newer quantization options - beyond the original scalar, product, and binary trio - has Qdrant introduced to fine-tune the compression/accuracy curve?
10What is Inline Storage, and how does embedding quantized vectors directly into HNSW graph nodes improve disk-based search performance?
11What is a multivector point, and how does it differ from a point with several named vectors?
12How does late-interaction scoring (as used by ColBERT-style models) with MaxSim differ from comparing two single dense vectors?
13Why is late-interaction reranking typically applied to a small candidate set rather than the entire collection?
14Design a three-stage retrieval pipeline using dense retrieval, sparse retrieval, fusion, and ColBERT reranking. What does each stage contribute?
03 / 14

What does the query-time parameter ef (search breadth) control, and how would you use it to trade off recall against latency?

ef is the dynamic candidate list size at query time

ef is the size of the dynamic candidate list maintained during the layer-0 best-first search. It is the single most important query-time knob in HNSW because it lets you trade recall for latency per request without touching the index. During search, the algorithm maintains two structures: a frontier of unexplored candidates ordered by distance, and a result set of the best nodes found so far, both bounded by ef. Larger ef means the search explores more of the graph before it terminates, which reduces the probability of missing a true nearest neighbor, at the cost of more distance computations. The result set is what gets returned as top-k, so ef must be at least as large as limit; Qdrant silently raises it to max(ef, limit) if you set it lower.

The reason this is the right knob to reach for is that it decouples recall from index structure. m and ef_construct are baked into the graph and changing them requires rebuilding; ef is evaluated fresh on every query and has essentially linear cost in distance computations and roughly linear cost in latency at a fixed vector size. That means you can have different ef for different endpoints: a search-as-you-type endpoint uses ef=32 for 3ms responses, while a nightly bulk scoring job uses ef=512 for maximum recall. The same collection serves both. The shape of the recall vs ef curve is concave and dataset-dependent: on most real datasets recall rises steeply between ef=16 and ef=128, then flattens. The knee of that curve is where you want your default; past it you are paying latency for fractions of a point of recall. You should measure this curve on your own data against exact ground truth, not assume the knee is at the same place as a blog post.

  1. 1

    ef is per-query and does not require a rebuild, unlike m and ef_construct.

  2. 2

    Effective ef is max(hnsw_ef, limit); setting it below limit has no effect.

  3. 3

    Cost scales roughly linearly with ef in distance computations, but wall-clock latency can scale worse if you are already CPU-bound or memory-bandwidth-bound.

  4. 4

    For quantized collections, ef interacts with oversampling and rescoring: a high ef with binary quantization can still underperform a moderate ef with full-precision rescoring.

The main alternative to raising ef is to improve the graph itself (higher m or ef_construct) at the cost of memory and a rebuild. If you have already rebuilt recently and memory is not the constraint, raising ef is almost always the cheaper move because it is reversible and per-request. The common mistake is setting ef very high to fix a recall problem that is actually caused by the embedding model or by aggressive payload filtering, not by HNSW. Another common mistake is assuming a higher ef always means higher latency - it does in aggregate, but for very small collections that fit in cache the difference can be in the microseconds, so it is worth measuring rather than assuming. A subtler one: on a multi-tenant collection, a single global ef can be wrong for both small and large tenants; if you cannot tune per tenant, a moderate ef with post-filtering on top can be better than a very high ef with heavy pre-filtering. Version note: the exact default of hnsw_ef has changed across releases and is not the same as limit - always set it explicitly in performance-critical paths.

javascript

Version-dependent note: query_points with SearchParams(hnsw_ef=...) is the qdrant-client 1.10+ API. On older clients the same parameter was passed to search() as search_params=SearchParams(hnsw_ef=...). The semantics are identical, but the call site differs, so pin your client version in your lockfile and do not copy snippets across major versions without checking.

Difficulty: 7/10
Topics: HNSW, Search Parameters, Vector Search Tuning

Scenario Questions

0-2 years experience
  1. 1

    You set hnsw_ef=5 on a collection and limit=10. Explain why the results are not obviously worse and what Qdrant actually did.

  2. 2

    A teammate wants to raise ef to 1000 to improve recall on a 100k-vector collection. What would you expect to happen to latency and recall, and would you approve the change?

2-5 years experience
  1. 1

    Your search endpoint has a 25ms p99 SLO. After a traffic spike, p99 is 60ms and you suspect ef is too high. How do you confirm, and how do you reduce latency without dropping recall below the product target?

  2. 2

    You run an A/B test where variant A uses ef=64 and variant B uses ef=256. Recall improves by 0.5 points but click-through is flat. What does this tell you about where the real bottleneck is?

5-8 years experience
  1. 1

    Design a per-query adaptive ef scheme that varies ef based on the query's estimated difficulty (e.g. embedding norm, filter cardinality, or a learned predictor). What signals would you use and how would you validate that it does not regress p99?

  2. 2

    You have a multi-tenant collection where tenants range from 1k to 50M vectors. Explain why a single global ef is wrong and propose a tenant-aware tuning strategy that does not require per-tenant collections.

8+ years experience
  1. 1

    You need to guarantee a recall SLA (e.g. recall@10 >= 0.95) with a hard p99 latency SLA. Describe a system that enforces both at runtime, including what happens when a query cannot satisfy both and how you decide which SLA to violate.

  2. 2

    Explain how you would build a closed-loop controller that adjusts ef per collection based on observed recall against sampled exact ground truth, and what stability problems you would expect from such a controller.

Follow-up Questions

  • You have a 40ms p99 budget and a 0.90 recall@10 target. How do you find the ef that satisfies both, and what do you do if no single ef satisfies both for all query types?
  • How does ef interact with oversampling and rescoring on a binary-quantized collection, and why can a higher ef sometimes not help at all?